package orm

import (
	"errors"
	"fmt"
	"net/url"
	"strings"
)

type Conf struct {
	HostPort    int
	MaxLifetime int
	MaxIdleTime int
	MaxOpenConn int
	MaxIdleConn int

	Type     string // 数据库类型，默认为mysql
	HostName string
	DataBase string
	UserName string
	PassWord string
	Charset  string
	TimeZone string
	Prefix   string
	DbPath   string // 仅用作 sqlite3 数据库
	Encrypt  bool   // 仅用作 mssql 数据库
	SslMode  bool   // 仅用作 pgsql 数据库
}

func (c *Conf) Check() error {
	if c.HostName == "" {
		return errors.New("主机名不能为空")
	}

	if c.HostPort <= 0 {
		c.HostPort = 3306
	}

	if c.MaxLifetime <= 0 {
		c.MaxLifetime = 100
	}

	if c.MaxIdleTime <= 0 {
		c.MaxIdleTime = 100
	}

	if c.MaxOpenConn <= 0 {
		c.MaxOpenConn = 100
	}

	if c.MaxIdleConn <= 0 {
		c.MaxIdleConn = 10
	}

	if c.Charset == "" {
		c.Charset = "utf8mb4"
	}

	if c.TimeZone == "" {
		c.TimeZone = "Asia/Shanghai"
	}

	if c.DataBase == "" {
		return errors.New("数据库名不能为空")
	}

	if c.UserName == "" {
		return errors.New("数据库用户名不能为空")
	}

	if c.PassWord == "" {
		return errors.New("数据库密码不能为空")
	}

	return nil
}

func (c *Conf) getPrefix() string {
	return c.Prefix
}

func (c *Conf) String() string {
	return c.driver()
}

func (c *Conf) driver() string {
	if c.Type == "" {
		c.Type = "mysql"
	}
	c.Type = strings.ToLower(c.Type)

	mapPool := map[string]string{
		"mysql":   fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=true&loc=%s", c.UserName, c.PassWord, c.HostName, c.HostPort, c.DataBase, c.Charset, url.QueryEscape(c.TimeZone)),
		"mssql":   fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;encrypt=%s;", c.HostName, c.UserName, c.PassWord, c.HostPort, c.DataBase, c.Encrypt),
		"pgsql":   fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s", c.HostName, c.HostPort, c.UserName, c.PassWord, c.DataBase, c.SslMode),
		"sqlite3": fmt.Sprintf("%s", c.DbPath),
	}

	if val, ok := mapPool[c.Type]; ok {
		return val
	}

	return mapPool["mysql"]
}
